﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PresentationTab.xaml.cs" company="arvystate.net">
//   arvystate.net
// </copyright>
// <summary>
//   Interaction logic for PresentationTab.xaml
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace PresentationAid.Tabs
{
    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Threading;

    using Kinect.Toolbox;

    using Microsoft.Kinect;

    using NLog;

    using PresentationAid.Core;
    using PresentationAid.Lib.Enums;
    using PresentationAid.Lib.GestureEngines;

    /// <summary>
    /// Interaction logic for PresentationTab
    /// </summary>
    public partial class PresentationTab
    {
        #region Static Fields

        /// <summary>
        /// The logger.
        /// </summary>
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        #endregion

        #region Fields

        /// <summary>
        /// The dispatcher timer.
        /// </summary>
        private readonly DispatcherTimer dispatcherTimer;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PresentationTab"/> class.
        /// </summary>
        public PresentationTab()
        {
            Logger.Trace("Init: PresentationTab");

            this.InitializeComponent();

            // Timer for UI updates
            Logger.Trace("InitDetail: DispatcherTimer - StartKinect, Interval: {0}", 200);

            this.dispatcherTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) };

            this.dispatcherTimer.Tick += this.Update;
            this.dispatcherTimer.Start();

            KinectSensorManager.Instance.KinectSensorActiveChanged += this.OnKinectSensorActiveChanged;
            KinectSensorManager.Instance.KinectSensorActiveStarted += this.OnKinectSensorActiveStarted;
            KinectSensorManager.Instance.KinectSensorActiveClosed += this.OnKinectSensorActiveClosed;
            KinectSensorManager.Instance.SkeletonFrameReady += this.OnSkeletonFrameReady;
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Returns step icon name
        /// </summary>
        /// <param name="step">
        /// Step setting
        /// </param>
        /// <returns>
        /// Step status <see cref="string"/>.
        /// </returns>
        public string GetStepSetting(int step)
        {
            ImageSource source;

            switch (step)
            {
                default:
                    source = this.StepOneIcon.Source;

                    break;
                case 2:
                    source = this.StepTwoIcon.Source;

                    break;
                case 3:
                    source = this.StepThreeIcon.Source;

                    break;
            }

            try
            {
                string fileName = System.IO.Path.GetFileName(source.ToString());

                if (fileName != null)
                {
                    return fileName.Replace("_32.png", string.Empty).Replace("2", string.Empty);
                }
            }
            catch (Exception ex)
            {
                Logger.Trace("MethodDetail: GetStepSetting - Step: {0}, Exception: {1}", step, ex.Message);
            }

            return string.Empty;
        }

        /// <summary>
        /// The set help buttons.
        /// </summary>
        /// <param name="helpText">
        /// The help text.
        /// </param>
        /// <param name="buttonTitle">
        /// The button title.
        /// </param>
        public void SetHelpButtons(string helpText, string buttonTitle)
        {
            if (string.IsNullOrEmpty(helpText))
            {
                if (this.GetStepSetting(1) == "error")
                {
                    this.HelpText.Text = "Where to get it?";
                }
                else if (this.GetStepSetting(2) == "error")
                {
                    this.HelpText.Text = "Why does this happen?";
                }
                else
                {
                    if (this.GetStepSetting(3) == "warning")
                    {
                        this.HelpText.Text = "Why does it say that?";
                    }
                    else if (this.GetStepSetting(3) == "error")
                    {
                        this.HelpText.Text = "Why does it say that?";
                    }
                    else
                    {
                        this.HelpText.Text = "Don't know how?";
                    }
                }
            }
            else
            {
                this.HelpText.Text = helpText;
            }

            if (string.IsNullOrEmpty(buttonTitle))
            {
                if (this.GetStepSetting(1) == "error")
                {
                    this.HelpButton.Content = "MICROSOFT STORE";
                }
                else if (this.GetStepSetting(2) == "error")
                {
                    this.HelpButton.Content = "GET HELP";
                }
                else
                {
                    if (this.GetStepSetting(3) == "warning")
                    {
                        this.HelpButton.Content = "GET ANSWER";
                    }
                    else if (this.GetStepSetting(3) == "error")
                    {
                        this.HelpButton.Content = "GET ANSWER";
                    }
                    else
                    {
                        this.HelpButton.Content = "START TUTORIAL";
                    }
                }
            }
            else
            {
                this.HelpButton.Content = buttonTitle;
            }

            Logger.Trace("Method: SetHelpButton HelpTitle: {0}, Text: {1}", this.HelpText.Text, this.HelpButton.Content);
        }

        /// <summary>
        /// Sets title of main page
        /// </summary>
        /// <param name="title">
        /// The title.
        /// </param>
        public void SetMainTitle(string title)
        {
            if (string.IsNullOrEmpty(title))
            {
                // Step 1 failed - display
                if (this.GetStepSetting(1) == "error")
                {
                    this.MainTitle.Text = "Sorry, you cannot present without Microsoft Kinect™ sensor.";
                }
                else if (this.GetStepSetting(2) == "error")
                {
                    this.MainTitle.Text = "Kinect™ must be able to see a presenter, so it can read your gestures.";
                }
                else
                {
                    if (this.GetStepSetting(3) == "warning")
                    {
                        if (KinectSensorManager.Instance.GestureEngine is ExtendedKeystrokeEngine)
                        {
                            this.MainTitle.Text =
                                "Extended Keystroke Engine might not work correctly with other applications.";
                        }
                        else
                        {
                            this.MainTitle.Text =
                                "Keystroke Gensture Engine is not fully supported, use Extended if possible.";
                        }
                    }
                    else if (this.GetStepSetting(3) == "error")
                    {
                        this.MainTitle.Text = "You need Microsoft PowerPoint™ running to begin the presentation!";
                    }
                    else
                    {
                        PowerPointEngine powerPointEngine =
                            KinectSensorManager.Instance.GestureEngine as PowerPointEngine;

                        if (powerPointEngine != null)
                        {
                            this.MainTitle.Text = "You can now start presentation by ";

                            switch (powerPointEngine.GetMapping(SlideShowCommand.StartStopSlideshow))
                            {
                                case GestureCommand.None:
                                    break;
                                case GestureCommand.JoinedHands:
                                    this.MainTitle.Text += "putting your hands together";
                                    break;
                                case GestureCommand.SwipeLeft:
                                    this.MainTitle.Text += "swiping your left hand right";
                                    break;
                                case GestureCommand.SwipeRight:
                                    this.MainTitle.Text += "swiping your right hand left";
                                    break;
                                case GestureCommand.Wave:
                                    this.MainTitle.Text += "waving either of your hand";
                                    break;
                            }

                            this.MainTitle.Text += "!";
                        }
                        else
                        {
                            this.MainTitle.Text = "You can now activate PowerPoint™ window and start with presentation!";
                        }
                    }
                }
            }
            else
            {
                this.MainTitle.Text = title;
            }

            Logger.Trace("Method: SetMainTitle - Title: {0}", this.MainTitle.Text);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The help button click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void HelpButtonClick(object sender, RoutedEventArgs e)
        {
            Logger.Debug("Help Button Click.");

            string helpButtonTitle = (string)this.HelpButton.Content;

            switch (helpButtonTitle)
            {
                case "START TUTORIAL":
                    MainWindow window = (MainWindow)Application.Current.MainWindow;
                    window.DisplayGestureWindow();

                    break;
                case "GET HELP":
                    Process.Start("http://presentationaid.codeplex.com/documentation");

                    break;
                case "MICROSOFT STORE":
                    Process.Start(
                        "http://www.microsoftstore.com/store/msstore/pd/Kinect-for-Windows/productID.244210600/");
                    break;
                case "GET ANSWER":
                    Process.Start("http://presentationaid.codeplex.com/faq");

                    break;
            }
        }

        /// <summary>
        /// The on kinect sensor active changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        private void OnKinectSensorActiveChanged(object sender, KinectSensorEventArgs args)
        {
            Logger.Debug("Event: KinectSensorActiveChanged - IsRunning: {0}", KinectSensorManager.Instance.IsRunning);

            // If active sensor is not running, we cannot do anything
            if (KinectSensorManager.Instance.IsRunning)
            {
                this.SetStepSetting(1, "check", "Connected and configured Microsoft Kinect™ sensor.");
            }
            else
            {
                this.SetStepSetting(1, "error", "Connect and configure Microsoft Kinect™ sensor.");
            }
        }

        /// <summary>
        /// The on kinect sensor active closed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        private void OnKinectSensorActiveClosed(object sender, KinectSensorEventArgs args)
        {
            Logger.Debug("Event: KinectSensorActiveClosed");

            this.SetStepSetting(1, "error", "Connect and configure Microsoft Kinect™ sensor.");
        }

        /// <summary>
        /// The on kinect sensor active started.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        private void OnKinectSensorActiveStarted(object sender, KinectSensorEventArgs args)
        {
            Logger.Debug("Event: KinectSensorActiveStarted");

            this.SetStepSetting(1, "check", "Connected and configured Microsoft Kinect™ sensor.");
        }

        /// <summary>
        /// Handles Step 3
        /// </summary>
        /// <param name="sender">
        /// Sender of the skeleton frame ready event
        /// </param>
        /// <param name="args">
        /// Event arguments
        /// </param>
        private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs args)
        {
            using (SkeletonFrame frame = args.OpenSkeletonFrame())
            {
                if (frame == null)
                {
                    this.SetStepSetting(2, "error", "Make sure Kinect™ can see a presenter.");

                    return;
                }

                Skeleton[] skeletons = null;

                frame.GetSkeletons(ref skeletons);

                if (skeletons.Any(s => s.TrackingState == SkeletonTrackingState.Tracked))
                {
                    this.SetStepSetting(2, "check", "The Kinect™ can clearly see and follow a presenter.");
                }
                else
                {
                    this.SetStepSetting(2, "error", "Make sure Kinect™ sensor can see a presenter.");
                }
            }
        }

        /// <summary>
        /// Changes Step settings
        /// </summary>
        /// <param name="step">
        /// Step number
        /// </param>
        /// <param name="icon">
        /// Step icon
        /// </param>
        /// <param name="title">
        /// Step title
        /// </param>
        private void SetStepSetting(int step, string icon, string title)
        {
            // Check step by title (so we do not update UI unless necessary)
            TextBlock[] stepTitles = new[] { this.StepOneText, this.StepTwoText, this.StepThreeText };

            if (stepTitles[step - 1].Text == title)
            {
                return;
            }

            Logger.Debug("Method: SetStepSetting - Step: {0}, Icon: {1}, Title: {2}", step, icon, title);

            switch (step)
            {
                case 1:
                    this.StepOneIcon.Source =
                        new BitmapImage(
                            new Uri(
                                "/PresentationAid;component/Resources/Images/Icons/" + icon + "_32.png", 
                                UriKind.RelativeOrAbsolute));

                    break;
                case 2:
                    this.StepTwoIcon.Source =
                        new BitmapImage(
                            new Uri(
                                "/PresentationAid;component/Resources/Images/Icons/" + icon + "_32.png", 
                                UriKind.RelativeOrAbsolute));

                    break;
                case 3:
                    this.StepThreeIcon.Source =
                        new BitmapImage(
                            new Uri(
                                "/PresentationAid;component/Resources/Images/Icons/" + icon + "_32.png", 
                                UriKind.RelativeOrAbsolute));

                    break;
            }

            stepTitles[step - 1].Text = title;

            this.SetMainTitle(string.Empty);
            this.SetHelpButtons(string.Empty, string.Empty);
        }

        /// <summary>
        /// Function updates presentation tab
        /// </summary>
        /// <param name="sender">
        /// Sender of the update event
        /// </param>
        /// <param name="eventArgs">
        /// Event arguments
        /// </param>
        private void Update(object sender, EventArgs eventArgs)
        {
            // Actions with PowerPoint Engine
            PowerPointEngine gestureEngine = KinectSensorManager.Instance.GestureEngine as PowerPointEngine;

            if (gestureEngine != null)
            {
                PowerPointEngine engine = gestureEngine;

                if (engine.IsRunning)
                {
                    this.SetStepSetting(
                        3, "check", "Microsoft PowerPoint™ " + engine.OfficeVersion + " is already running.");
                }
                else
                {
                    this.SetStepSetting(3, "error", "Microsoft PowerPoint™ needs to be launched.");
                }
            }
            else if (KinectSensorManager.Instance.GestureEngine is ExtendedKeystrokeEngine)
            {
                // Actions with ExtendedKeystroke engine
                bool isPowerPointRunning = false;

                foreach (Process clsProcess in Process.GetProcesses())
                {
                    if (!clsProcess.ProcessName.ToLower().Contains("powerpnt"))
                    {
                        continue;
                    }

                    isPowerPointRunning = true;

                    break;
                }

                if (isPowerPointRunning)
                {
                    this.SetStepSetting(3, "check", "Microsoft PowerPoint™ is currently running.");
                }
                else
                {
                    this.SetStepSetting(3, "warning2", "Other applications are not fully supported.");
                }
            }
            else
            {
                this.SetStepSetting(3, "warning2", "Keystroke Gesture Engine is not recommended.");
            }
        }

        #endregion
    }
}